/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_cli.h"
#include "ak_socket.h"
#include "ak_appl.h"

static 	int 	_gTraceLvl_AppL = TRACELVL_WARNING;

static char * 	_gCmdNExist_AppAgt =	"command not found";

/* The Application/Module Status:
**	0: Out of Service 
**	1: In Service 
*/
#define S_SAP_OOS 	0
#define S_SAP_INS 	1

typedef enum _t_sapType{
	E_SAP_T_PRIVATE	= 0,
	E_SAP_T_PROTECT	= 1,
	E_SAP_T_PUBLIC 	= 2
}_t_sapType;

typedef enum _t_sapFlag{
	E_SAP_F_INTERAL	= 0,	/* Use the Internal App IP to Communicate */
	E_SAP_F_EXTERAL	= 1,	/* Use the External APP IP to Communicate */
}_t_sapFlag;

typedef struct _t_sapInfo{
	/* The IP Addr info will be Collect by the Agent */
	_t_sapType	sapType;
	_t_sapFlag	sapFlag;
	
	unsigned int	sapId:	16,
					port :	16;
}_t_sapInfo;


/* -----------------------------------------------------------------------
** 	Application Level's OAM info
**	Each Application will have a Daemon to Moniter the MOD/SAP status.
** 	The Daemon will Relay the CLI Interface.
**	The Module's Load & Dependcency Check is done by the Dameon.
**	the Daemon will moniter the all the Module's Runtime OOS/INS.
**
** 	IP Address:
**	We have 3 types IP Address.
** 	OAM 	IP.
**	APP  	IP. Ext
**	APP  	IP. Int
**	For an APP act as a Gateway, Such as TS. Will have 2 APP IP, Ext & Int, 
**	to inter-Comm with the Web/ACS with Ext IP.
**	to inter-Comm with the SQL/BS with Int IP.
** 	This is Decide by the Agent.
**	
*/
#define _SAGT_APP_TASK_STACK 		0X100000
#define _SAGT_APP_TASK_PRI 			90

#define _SAGT_APP_MOD_MAX  		16		/* Each Application Process could support Max 16 Module. */
#define _SAGT_MOD_SAP_MAX  		8		/* Each Moudle's could support Max 8 Service. */

typedef struct _t_appService{
	_t_bnode 		sapNode;

	_t_sapInfo 	sapInfo;
	unsigned int 	ipAddr;				/* Should always be the Application IP */
}_t_appService;


typedef struct _t_appModInfo{
	/* Module Info */
	unsigned int 	cpu;			/* Module's Cpu Cost Ratio, xx%, use the xx Part */
	unsigned int 	mem;			/* Module's Memory Cost */
	unsigned int 	thread;			/* Module's Thread Count */
}_t_appModInfo;


typedef struct _t_appModule{
	_t_bnode 			modNode;
	_t_bnode 			hashNode;

	unsigned int 		modId;		/* Moudle Id in order to diff each other, hash It....*/
	
	/* Service Active Queue*/
	_t_blist 			sapQue;
	
	/* Service Pool */
	_t_blist 			sapPool;
	_t_appService 		service[_SAGT_MOD_SAP_MAX];

	/* Custom Info & Register Callback */
	_t_appModInfo 		modInfo;
	_t_appModReg 		modReg;

	/* CLI */
	_t_cliCmdTbl 		cmdTbl;	
}_t_appModule;

static 	void 	_SAgtApp_ModInit(_t_appModule * pModule)
{
	int 				i;
	_t_blist 		 * 	pQue;
	_t_appService * 	pService;

	SYS_MEMZERO(pModule, sizeof(_t_appModule));

	BLIST_INIT(&(pModule->sapQue));
	pQue = &(pModule->sapPool);
	BLIST_INIT(pQue);
	for(i=0, pService = pModule->service; i<_SAGT_MOD_SAP_MAX; i++, pService++){
		BLST_ADD2T(pQue, &(pService->sapNode));
	}

	BLIST_INIT(&(pModule->cmdTbl.cmdQue));
	pQue = pModule->cmdTbl.hashQue;
	for(i=0; i<_S_CLI_CMD_HASH; i++, pQue++){
		BLIST_INIT(pQue);	
	}

	return;
}

int 	SAgtApp_ModRegCmd(void * pModule, _t_cliCmdReg * pCmdReg)
{
	_t_appModule 	* pMod;
	_t_cliCommand	* pCommand;
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	char 			* pCmdStr;
	int 			  i, len, ret, hashKey;
	
	if(!pModule || !(pCmdReg) || !(pCmdReg->func.cbProc)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command Register Error.\n");
		return -1;
	}
	
	pMod = (_t_appModule *)pModule;
	/* Check Cmd */
	pCmdStr = pCmdReg->cmd;
	if(pCmdStr[0] == '\0'){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command: Error.\n");
		return -1;		
	}
	if(	SStrJ_Avail(pCmdStr)== -1 ){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command:[%s] Illegal.\n", pCmdStr);
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pMod->cmdTbl.hashQue[hashKey]);

	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command:[%s] Dup.\n", pCmdStr);
			return -1;
		}
	}

	/* Alloc the Cmd Struct */
	pCommand = SYS_MALLOC(sizeof(_t_cliCommand));
	if(!pCommand){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command:[%s] Alloc Fail.\n", pCmdStr);
		return -1;
	}
	SYS_MEMCPY(&(pCommand->cmdReg), pCmdReg, sizeof(_t_cliCmdReg));

	/* Add 2 Que */
	pQue 	= &(pMod->cmdTbl.cmdQue);
	BLST_ADD2T(pQue, &(pCommand->cmdNode));
	pQue 	= &(pMod->cmdTbl.hashQue[hashKey]);
	BLST_ADD2T(pQue, &(pCommand->hashNode));
	return 0;
	
}

static 	int 	_SAgtApp_ModCmd_Ls(_t_appModule * pModule, 
									char * outBuf, 
									int    outLen)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand	* pCommand;
	_t_cliElemRsp	* pRspElem;
	int 			i, count, total;
	
	if((!pModule) || (!outBuf)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Error.\n");
		return -1;
	}

	/* Init the pRspElem */
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_LCMD;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	outLen -= sizeof(_t_sysMsgElem) + 2; /* For '\n', '\0' */
	outBuf 	= pRspElem->reqRsp;
	
	pQue  = &(pModule->cmdTbl.cmdQue);
	count = pQue->count;
	total = 0;

	for(i=0, pNode = pQue->next; i<count; i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, cmdNode, pNode);

		if(strlen(pCommand->cmdReg.cmd) == 0)
			continue;

		total += SYS_SNPRINTF(outBuf+total, outLen - total, _CLI_FMT_APP_COMMAND, pCommand->cmdReg.cmd);

		/* Judge Buffer */
		if(total >= outLen){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module:[%d] CmdLs Rsp Buffer [%d - %d] Overflow.\n", 
				pModule->modId, total, outLen);
			break;
		}
	}
	
	pRspElem->reqRsp[total]  	= '\0';
	total += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + total;
		
	return pRspElem->msgElem.length;
}

static 	int 	_SAgtApp_ModCmd_Exec(_t_appModule * pModule, 
									char * outBuf, 
									int    outLen,
									char * pCmdStr,
									char * pParam)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand* pCommand;
	_t_cliElemRsp* pRspElem;
	_t_cbentry 		* pCbEntry;
	int 			i, len, ret, hashKey;
	
	if((!pModule) || (!outBuf) || (!pCmdStr) || (!pParam) || (outLen <= 0)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Error.\n");
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pModule->cmdTbl.hashQue[hashKey]);

	
	for(i=0, ret=-1, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module Command:[%s].\n", pCmdStr);
			ret = 0;
			break;
		}
	}
	
	if(ret == -1){
		/* Judge Buffer */
		if((sizeof(_t_sysMsgElem) + strlen(_gCmdNExist_AppAgt)) >= outLen){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module:[%d] CmdExec Rsp Buffer Overflow.\n", pModule->modId);
			return -1;
		}
		/* Init the pRspElem */
		pRspElem = (_t_cliElemRsp *)outBuf;

		len = strlen(_gCmdNExist_AppAgt);
		pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
		pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
		pRspElem->msgElem.reserv= 0;
		SYS_MEMCPY(pRspElem->reqRsp, _gCmdNExist_AppAgt, len);
		pRspElem->reqRsp[len] = '\0';
		len += 1;
		pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;
		ret  	= (sizeof(_t_sysMsgElem) + len);
	}

	else{
		pCbEntry = &(pCommand->cmdReg.func);
		if(pCbEntry->cbProc){
			/* Init the Output Buf for CallBack Entry */
			pRspElem = (_t_cliElemRsp *)outBuf;
			pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
			pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
			pRspElem->msgElem.reserv= 0;
			pRspElem->reqRsp[0] = '\0';

			outBuf  += sizeof(_t_sysMsgElem);
			outLen 	-= sizeof(_t_sysMsgElem) + 2;
			ret = pCbEntry->cbProc(	pCbEntry->pArg,
									pCbEntry->lArg,
									outBuf,
									outLen,
									pParam);
			if( (ret >= 0) && (ret < outLen)){
				pRspElem->reqRsp[ret]='\0';
				ret += 1;
				pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + ret;
				ret += sizeof(_t_sysMsgElem);
			}
			else{
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Module:[%d] CmdExec Rsp Buffer [%d - %d] Overflow.\n", 
					pModule->modId, ret, outLen);
				ret = -1;
			}
		}
	}
	
	return ret;
}


/* =====================================================================
** FCast App Agent Interface
*/

#define _SAGT_APP_HASH 		4
typedef struct _t_appAgt{
	/* Module Active Queue*/
	_t_blist 			modQue;
	_t_blist 			hashQue[_SAGT_APP_HASH];

	/* Module Pool */
	_t_blist 			modPool;
	_t_appModule 		module[_SAGT_APP_MOD_MAX];

	/* Command Info */
	_t_cliCmdTbl 	cmdTbl;
	
	/* Process Info */
	int 			bInit;
	
	_t_sysCS 		agtLock;

	_t_sysTask		taskCli;
	_t_sysTask 		taskCtrl;
	
	char 			agtName[S_APP_MAX_NAME+1];

	/* Cli Info */
	int 				sockCli;
	S_SOCKET_ADDRUX 	addrCli;
	S_SOCKET_ADDRUX 	addrCtrl;
}_t_appAgt;

static 	_t_appAgt  	_gAgt_App;

#define _SAGT_APP_WT_INIT 		10		
#define _SAGT_APP_TO_INIT 		50		/* Probe 50ms */
#define _SAGT_APP_WT_FINI 		10		
#define _SAGT_APP_TO_FINI 		50		/* Probe 50ms */
#define _SAGT_APP_TO_HEATBEAT 	5000 	/* HeatBeat every 5s */

static 	int 	_SAgtApp_Reg(_t_appAgt * 	pAppAgt)
{
	_t_castMsgHdr 	* 	pMsgHdr;
	char 			* 	pPos;
	int 				len;
	unsigned char 		msgBuf[_SCAST_MSG_MAXLEN];
	
	pMsgHdr = (_t_castMsgHdr *)(msgBuf);
	pMsgHdr->type = _SCAST_APP_REG_REQ;
	pPos 	= (char *)(pMsgHdr->data);
	len 	= strlen(pAppAgt->agtName);
	strncpy(pPos, pAppAgt->agtName, len); 
	pPos[len]= '\0';
	len += 1;
	pMsgHdr->length = len + sizeof(_t_castMsgHdr);

	SockTx_Unix(pAppAgt->sockCli, msgBuf, (pMsgHdr)->length, &(pAppAgt->addrCtrl));
	return 0;
}

static 	int 	_SAgtApp_UnReg(_t_appAgt * 	pAppAgt)
{
	_t_castMsgHdr 	* 	pMsgHdr;
	char 			* 	pPos;
	int 				len;
	unsigned char 		msgBuf[_SCAST_MSG_MAXLEN];
	
	pMsgHdr = (_t_castMsgHdr *)(msgBuf);
	pMsgHdr->type = _SCAST_APP_UNR_REQ;
	pPos 	= (char *)(pMsgHdr->data);
	len 	= strlen(pAppAgt->agtName);
	strncpy(pPos, pAppAgt->agtName, len); 
	pPos[len]= '\0';
	len += 1;
	pMsgHdr->length = len + sizeof(_t_castMsgHdr);

	SockTx_Unix(pAppAgt->sockCli, msgBuf, (pMsgHdr)->length, &(pAppAgt->addrCtrl));
	SYS_SLEEP(_SAGT_APP_WT_FINI * _SAGT_APP_TO_FINI);

	return 0;
}


/* -----------------------------------------------------------------------
** 	Application Signal Handler.
** 	The App Agent Signal Handler is a Stub. 
**	Go through all the modules' Fault Process Functions, if not NULL, Call them with signo.
*/
static 	int 	_gSigCnt_App = 0;
static 	int 	_gSigTbl_App[]={
	SIGBUS,
	SIGFPE,
	#if 0
	SIGHUP,
	#endif
	SIGILL,
	SIGINT,
	SIGIOT,
	SIGQUIT,
	SIGSEGV,
	SIGTERM,
	SIGTRAP,
	SIGUSR1,
	SIGUSR2
};

static 	void 	_SAgtApp_SigHandler(int signo)
{
	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	_t_appModReg* 	pModReg;
	int 				i, ret, count;
	
	if(_gSigCnt_App++){
		/* Avoid Double Fault */
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "App Signal %d During Cleanup. Exit!\n", signo);
		exit(1);
	}
	
	/* Check AppAgt Init */
	if(_gAgt_App.bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		exit(2);
	}	

	/* Terminate */
	pQue 	= &(_gAgt_App.modQue);
	count 	= pQue->count;
	SYS_ENTER_CS(&(_gAgt_App.agtLock));
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "AppAgt [%d] Mods Recv SigNo:%d.\n", count, signo);
	for(i=0, pNode=pQue->next; i<count; i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, modNode, pNode);
		pModReg = &(pModule->modReg);
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "FaultHandler Mod[%d] .\n", pModReg->modId);
		if(pModReg->cbFault.cbProc){
			ret = pModReg->cbFault.cbProc(pModReg->cbFault.pArg, 
									  		pModReg->cbFault.lArg, signo);
			if(ret != 0){
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Mod[%d] FaultProc Error.\n", pModReg->modId);
			}
		}
	}
	SYS_LEAVE_CS(&(_gAgt_App.agtLock));
	
	_SAgtApp_UnReg(&_gAgt_App);

	SYS_CLOSE(close, 	_gAgt_App.sockCli);
	exit(0);
}


/* -----------------------------------------------------------------------
**	Command Table Of AppAgt
**
*/
static 	int 	_SAgtApp_RegCmd(_t_appAgt*pAppAgt, _t_cliCmdReg * pCmdReg)
{
	_t_cliCommand* pCommand;
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	char 			* pCmdStr;
	int 			  i, len, ret, hashKey;
	

	/* Check Cmd */
	pCmdStr = pCmdReg->cmd;
	if(pCmdStr[0] == '\0'){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command: Error.\n");
		return -1;		
	}
	if(	SStrJ_Avail(pCmdStr)== -1 ){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command:[%s] Illegal.\n", pCmdStr);
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pAppAgt->cmdTbl.hashQue[hashKey]);

	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command:[%s] Dup.\n", pCmdStr);
			return -1;
		}
	}

	/* Alloc the Cmd Struct */
	pCommand = SYS_MALLOC(sizeof(_t_cliCommand));
	if(!pCommand){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command:[%s] Alloc Fail.\n", pCmdStr);
		return -1;
	}
	SYS_MEMCPY(&(pCommand->cmdReg), pCmdReg, sizeof(_t_cliCmdReg));

	/* Add 2 Que */
	pQue 	= &(pAppAgt->cmdTbl.cmdQue);
	BLST_ADD2T(pQue, &(pCommand->cmdNode));
	pQue 	= &(pAppAgt->cmdTbl.hashQue[hashKey]);
	BLST_ADD2T(pQue, &(pCommand->hashNode));
	return 0;
	
}

static 	int 	SAgtApp_RegCmd(void * pApplication, _t_cliCmdReg * pCmdReg)
{
	_t_appAgt * pAppAgt;
	int 				ret;
	
	if(!pApplication || !(pCmdReg) || !(pCmdReg->func.cbProc)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command Register Error.\n");
		return -1;
	}
	
	pAppAgt = (_t_appAgt *)pApplication;
	
	SYS_ENTER_CS(&(pAppAgt->agtLock));
	ret = _SAgtApp_RegCmd(pAppAgt, pCmdReg);
	SYS_LEAVE_CS(&(pAppAgt->agtLock));

	return ret;
}

static 	int 	_SAgtApp_ShowStat(void * pArg, int lArg, void * pApplication, 
										 char * outBuf, int outLen)
{
	_t_appAgt* 	pAppAgt;
	_t_appModule	* 	pModule;
	_t_bnode 		* 	pNode;
	_t_blist 		* 	pQue;
	
	int i, len, count;

	if(!pApplication || !(outBuf) || (outLen <= 0)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Application Command Error.\n");
		return -1;
	}
	pAppAgt = (_t_appAgt *)pApplication;
	len = 0;

	pQue = &(pAppAgt->modQue);
	count= pQue->count;
	for(i=0, pNode=pQue->next; 	i<count; 	i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, modNode, pNode);
		len += SYS_SNPRINTF(outBuf+len, outLen - len, "[Module %02d]:[%d]\n",
			i, pModule->modId);
		if(len >= outLen)
			break;
	}

	return len;
}

static 	_t_cliCmdReg 	_gCmd_AgtApp[]={
		{"stat", {(int (*)())_SAgtApp_ShowStat, NULL, 0}}
};

int 	SAgtSock_InitUdp(int * pSock, S_SOCKET_ADDRIN * pAddrIn, short port)
{
	int 	i, sockId;
	/* 
	**
	** 	Relay Socket 
	**
	*/
	sockId = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if(sockId == -1){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Agt Socket Udp: Create Fail:[%d]\n", errno);
		SYS_CLOSE(close, sockId);
		return -1;
	}
	/* Binding Socket */
	SYS_MEMZERO(pAddrIn, sizeof(S_SOCKET_ADDRIN));
	pAddrIn->sin_family		= AF_INET;
	pAddrIn->sin_port		= htons(port);
	pAddrIn->sin_addr.s_addr= htonl(INADDR_ANY);
	if(bind(sockId, (struct  sockaddr *)pAddrIn, sizeof(S_SOCKET_ADDRIN)) == -1){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Agt Socket Udp: Bind Fail:[%d]\n", errno);
		/* Close the Handle */
		SYS_CLOSE(close, sockId);
		return -1;
	}
	
	S_SOCK_SET_NONBLOCK(sockId, i);
	S_SOCK_SET_SNDBUF(sockId, i, 0XC0000);		
	S_SOCK_SET_RCVBUF(sockId, i, 0X400000);		
	S_SOCK_SET_NOCHKSUM(sockId, i);
	S_SOCK_SET_LOWDELAY(sockId, i);
	*pSock = sockId;
	return 0;
}

	
int 	SAgtSock_InitUnix(int * pSock, S_SOCKET_ADDRUX * pAddrUx, char * summix)
{
	int 	i, sockId;
	
	sockId = socket( AF_UNIX, SOCK_DGRAM, 0);
	if(sockId == -1){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Agt Unix Socket: Create Fail:[%d]\n",errno);
		return -1;
	}

	_S_AGT_SOCKUN_INIT(pAddrUx, summix, i);

	/* Unlink & Binding */
#if 1
	unlink(pAddrUx->sun_path);
#endif
	*pSock = sockId;
	i = bind(sockId, ( struct sockaddr * )(pAddrUx), sizeof(S_SOCKET_ADDRUX)) ;
	if(i == -1){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "Agt Unix Socket: [%s] Bind Fail:[%d]\n", 
			pAddrUx->sun_path, errno);

		/* Close the Handle */
		SYS_CLOSE(close, sockId);
		return -1;
	}
	S_SOCK_SET_SNDBUF(sockId, i, 0XC0000);		
	S_SOCK_SET_NONBLOCK(sockId, i);	
	*pSock = sockId;
	return 0;
}


/* -----------------------------------------------------------------------
** 	Application CLI Socket.
**
*/
static 	int 	_SAgtApp_SockInit(_t_appAgt * pAppAgt)
{
	int 	ret;
	/* 
	**	Cli Socket 
	*/
	_S_AGT_SOCKUN_INIT(&(pAppAgt->addrCtrl), "root.ctrl", ret);
	ret = SAgtSock_InitUnix(&(pAppAgt->sockCli), &(pAppAgt->addrCli), pAppAgt->agtName);

	return ret;
}


/* -----------------------------------------------------------------------
** 	Application Agent Init.
*/
static 	int 	_SAgtApp_Init(_t_appAgt * pAppAgt, char * appName)
{
	int 			i, len;
	_t_blist 	* 	pQue;
	_t_appModule*	pMod;
	
	if(pAppAgt->bInit != 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Init Already.\n");
		return -1;
	}
	
	if((appName == NULL) ||
		((len = strlen(appName)) >= S_APP_MAX_NAME)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Name Error.\n");
		return -1;
	}

	if(	SStrJ_Avail(appName)== -1 ){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Name:[%s] Illegal.\n", appName);
		return -1;
	}

	/* Normalize the Agent Name */
	strncpy(pAppAgt->agtName, 	appName, len);
	pAppAgt->agtName[len] = '\0';

	/* Cli Socket Info */
	if(_SAgtApp_SockInit(pAppAgt) == -1){
		return -1;
	}
	
	/* Init the Agt Info */
	SYS_INIT_CS(&(pAppAgt->agtLock));
	
	/* Module */
	BLIST_INIT(&(pAppAgt->modQue));	
	for(i=0; i<_SAGT_APP_HASH; i++){
		BLIST_INIT(&(pAppAgt->hashQue[i]));	
	}
	pQue=&(pAppAgt->modPool);
	BLIST_INIT(pQue);
	for(i=0, pMod=pAppAgt->module; 
		i<_SAGT_APP_MOD_MAX; 	i++, pMod++){

		_SAgtApp_ModInit(pMod);
		BLST_ADD2T(pQue, &(pMod->modNode));
	}

	/* Command Table */
	pQue  = &(pAppAgt->cmdTbl.cmdQue);
	BLIST_INIT(pQue);	
	for(i=0, pQue=pAppAgt->cmdTbl.hashQue; 
		i<_S_CLI_CMD_HASH; 	i++, pQue++){
		BLIST_INIT(pQue);	
	}

	/* Init the Command */
	len = _N_ARRAY(_gCmd_AgtApp);
	for(i=0; i<len; i++){
		SAgtApp_RegCmd(pAppAgt, &(_gCmd_AgtApp[i]));
	}

	/* Signal Exception Handler */
	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "App SigHandler %d Fail.\n", SIGPIPE);
		return -1;
	}
	len = _N_ARRAY(_gSigTbl_App);
	for(i=0; i<len; i++){
		if(signal(_gSigTbl_App[i], _SAgtApp_SigHandler) == SIG_ERR){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "App SigHandler %d Fail.\n", _gSigTbl_App[i]);
			return -1;
		}
	}

	pAppAgt->bInit = 1;
	return 0;
}

static 	int 	_SAgtApp_ModAdd(_t_appAgt * pAppAgt,
										int modId, 
										_t_appModReg * pModReg)
{
	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	int 				i, hashKey, ret;

	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	/* Check the Mod String */
	if(	pModReg->modStr && (pModReg->modStr[0] != 0) &&
		(SYS_STRLEN(pModReg->modStr) < S_APP_MAX_NAME)	){

		/* Hash ModId to Check if Already Reg */
		hashKey = modId%_SAGT_APP_HASH;
		pQue = &(pAppAgt->hashQue[hashKey]);

		ret = 0;
		for(i=0, pNode=pQue->next; 
			i<pQue->count; 
			i++, pNode=pNode->next){
			pModule = _O_PARENT(_t_appModule, hashNode, pNode);
			if(pModule->modId == modId){
				ret = -1;
				break;
			}
		}

		if(ret == -1){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt ModId Dup %d.\n", modId);
			return -1;
		}
		/* Alloc a Module */
		pQue = &(pAppAgt->modPool);
		pModule = (_t_appModule *)BLST_GET(pQue);

		if(pModule == NULL){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Module Alloc Fail.\n");
			return -1;
		}

		pModule->modId = modId;
		SYS_MEMCPY(&(pModule->modReg), pModReg, sizeof(_t_appModReg));
		/* Dup the String */
		pModule->modReg.modStr = SYS_STRDUP(pModReg->modStr);
		
		/* Add to Que & Hash */
		BLST_ADD2T(&(pAppAgt->modQue), &(pModule->modNode));
		pQue = &(pAppAgt->hashQue[hashKey]);
		BLST_ADD2T(pQue, &(pModule->hashNode));
		return 0;
	}

	return -1;
}


extern 	int 	_SAgtApp_ModDel(_t_appAgt * pAppAgt, int modId);
int 	_SAgtApp_ModDel(_t_appAgt * pAppAgt, int modId)
{
	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	int 				i, hashKey, flag;
	
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	/* Hash ModId to Check if Already Reg */
	hashKey = modId%_SAGT_APP_HASH;
	pQue = &(pAppAgt->hashQue[hashKey]);
	
	flag = 0;
	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, hashNode, pNode);
		if(pModule->modId == modId){
			flag = 1;
			break;
		}
	}
	
	if((flag == 1) && pModule){
		BLST_DEL(pQue, &(pModule->hashNode));
		BLST_DEL(&(pAppAgt->modQue), &(pModule->modNode));
		return 0;
	}

	return -1;
}


static 	_t_appModule * 	_SAgtApp_ModGet(_t_appAgt * pAppAgt,
										int modId)
{
	_t_appModule * 	pModule;
	_t_appModule * 	pRet;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	int 				i, hashKey, flag;
	
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return NULL;
	}	

	/* Hash ModId to Check if Already Reg */
	hashKey = modId%_SAGT_APP_HASH;
	pQue = &(pAppAgt->hashQue[hashKey]);
	
	flag = 0;
	pRet = NULL;
	
	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, hashNode, pNode);
		if(pModule->modId == modId){
			pRet = pModule;
		}
	}
	
	return pRet;
}


static 	int 	_SAgtApp_ModReg(_t_appAgt * pAppAgt,
										_t_appModReg  *	pReg)
{
	int ret;
	
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	if(pReg){
		SYS_ENTER_CS(&(pAppAgt->agtLock));
		ret = _SAgtApp_ModAdd(pAppAgt, pReg->modId, pReg);
		SYS_LEAVE_CS(&(pAppAgt->agtLock));
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Register [1] Mod.\n");

		return 0;
	}

	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Reg Info Error.\n");
	return -1;
}


static 	int 	_SAgtApp_ModRegA(_t_appAgt * pAppAgt,
								_t_appModReg ** ppReg, int count)
{
	int 	i, ret;
	_t_appModReg * pReg;
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	if(ppReg && (count > 0)){
		SYS_ENTER_CS(&(pAppAgt->agtLock));
		for(i=0; i<count; i++, ppReg++){
			pReg = *ppReg;
			if(pReg){
				ret = _SAgtApp_ModAdd(pAppAgt, pReg->modId, pReg);
			}
		}
		SYS_LEAVE_CS(&(pAppAgt->agtLock));
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Register [%d] Mods.\n", count);
		return 0;
	}
	
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Reg Info Error.\n");
	return -1;
}


/* -----------------------------------------------------------------------
** 	Application Agent Module Exec
**	1. Check Module's Ctor, if not NULL, Call It.
**	2. Check Module's Probe, if not NULL, Call It. Wait Module's state is OK (In Service).
**	3. Go Through to Next Module.
**	4. Now all Modules have Inited. 
**	5. Go Through All Modules' HeartBeat, if not NULL, Call them. Periodcly Check the Module's State is OK.
*/
static 	void * 	_SAgtApp_Cli(_t_appAgt* pAppAgt);

static 	int 	_SAgtApp_Exec(_t_appAgt * pAppAgt, _t_cbentry * pCbPost)
{
	int 				i, j, count, ret;
	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	_t_appModReg* 	pModReg;

	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	/* Step 1. Let's Start all Application */
	pQue 	= &(pAppAgt->modQue);
	count 	= pQue->count;

	SYS_ENTER_CS(&(pAppAgt->agtLock));
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "AppAgt Total [%d] Mods.\n", count);
	for(i=0, pNode=pQue->next; i<count; i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, modNode, pNode);
		pModReg = &(pModule->modReg);
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "Loading Mod[%d] .\n", pModReg->modId);
		if(pModReg->cbCtor.cbProc){
			ret = pModReg->cbCtor.cbProc(pModReg->cbCtor.pArg, 
									  	pModReg->cbCtor.lArg);
			if(ret != 0){
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Init Mod[%d] Error.\n", pModReg->modId);
				return -1;
			}
		}

		/* Now Let's Wait the Probe State Succ */
		ret = 0;
		if(pModReg->cbProbe.cbProc){
			j = 0;
			while(	(j < _SAGT_APP_WT_INIT) &&
					(pModReg->cbProbe.cbProc(pModReg->cbProbe.pArg, 
									  		 pModReg->cbProbe.lArg) != 0)){
				SYS_SLEEP(_SAGT_APP_TO_INIT);
				++j;
			}
			if(j >= _SAGT_APP_WT_INIT){
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Init Mod[%d] State Error.\n", pModReg->modId);
				ret = -1;
			}
		}

		/* Now Let's Call the CmdReg to Register all Command for CLI */
		if(ret == 0){
			if(pModReg->cbCmdReg.cbProc){
				ret = pModReg->cbCmdReg.cbProc( pModReg->cbCmdReg.pArg,
												pModReg->cbCmdReg.lArg, 
												pModule);
			}
		}
		
	}
	SYS_LEAVE_CS(&(pAppAgt->agtLock));

	/* Step 3. Let's Spawn the CLI */
	STASK_CRATE((pAppAgt->taskCli), 
				_SAGT_APP_TASK_STACK, 
				_SAGT_APP_TASK_PRI, 
				_SAgtApp_Cli, 
				pAppAgt);

	/* Step 4. Let's Register the Application */
	_SAgtApp_Reg(pAppAgt);

	/* Step 5. App Modules has been Initialised, Post Proce, User custom */
    if(pCbPost && (pCbPost->cbProc)){
        pCbPost->cbProc(pCbPost->pArg, pCbPost->lArg);
    }
	
	/* Step 6. Let's Start HearBeat all Application */
	do{
		SYS_SLEEP(_SAGT_APP_TO_HEATBEAT);
		SYS_ENTER_CS(&(pAppAgt->agtLock));
		for(i=0, pNode=pQue->next; i<count; i++, pNode=pNode->next){
			pModule = _O_PARENT(_t_appModule, modNode, pNode);
			pModReg = &(pModule->modReg);
			if(pModReg->cbHeatBeat.cbProc){
				ret = pModReg->cbHeatBeat.cbProc(pModReg->cbHeatBeat.pArg, 
										  		pModReg->cbHeatBeat.lArg);
			}
		}
		SYS_LEAVE_CS(&(pAppAgt->agtLock));
		
	}while(1);

	return 0;
}

/* -----------------------------------------------------------------------
** 	Application Agent Module Fini
** 	Go Through all Modules' Dtor, if not NULL, Call them.
*/

static 	int 	_SAgtApp_Fini(_t_appAgt * pAppAgt)
{
	int 				i, j, count, ret;
	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	_t_appModReg* 	pModReg;
	
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return -1;
	}	

	/* Go Through All Modules' Dtor */
	pQue 	= &(pAppAgt->modQue);
	count 	= pQue->count;

	SYS_ENTER_CS(&(pAppAgt->agtLock));
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "AppAgt Total [%d] Mods.\n", count);
	for(i=0, pNode=pQue->next; i<count; i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, modNode, pNode);
		pModReg = &(pModule->modReg);
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_NORMAL, "Fini Mod[%d] .\n", pModReg->modId);
		if(pModReg->cbDtor.cbProc){
			ret = pModReg->cbDtor.cbProc(pModReg->cbDtor.pArg, 
									  		pModReg->cbDtor.lArg);
			if(ret != 0){
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Fini Mod[%d] Error.\n", pModReg->modId);
				return -1;
			}
		}

		/* Now Let's Wait the Probe State Succ */
		if(pModReg->cbProbe.cbProc){
			j = 0;
			while(	(j < _SAGT_APP_WT_FINI) &&
					(pModReg->cbProbe.cbProc(pModReg->cbProbe.pArg, 
									  		 	pModReg->cbProbe.lArg) != -1)){
				SYS_SLEEP(_SAGT_APP_TO_FINI);
				++j;
			}
			if(j >= _SAGT_APP_WT_FINI){
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Fini Mod[%d] State Error.\n", pModReg->modId);
			}
		}
	}
	SYS_LEAVE_CS(&(pAppAgt->agtLock));

	/* UnRegister */
	_SAgtApp_UnReg(pAppAgt);
	
	/* Close the Handle */
	SYS_CLOSE(close, 	pAppAgt->sockCli);

	return 0;
}


/* -----------------------------------------------------------------------
**	CLI Of AppAgt
** 	The App Agent CLI Stub. 
**	Go through all the modules' Symbol Table, [command str  -->  command func].
**	The Symbol Table use Hash to optimize the Looking up Speed.
**
*/
static 	int 	_SAgtApp_CliModGet(_t_appAgt * 	pAppAgt, 
											char * pPath, 	int lenPath,
											_t_appModule**  ppModule,
											char * pSubPath)
{
	char 			* 	pPos;
	_t_appModule * 	pModule;
	char 				modName[S_APP_MAX_NAME + 1];
	int 				lenApp;
	int 				modId;
	if((pPath[0] != '/') || (pPath[lenPath-1] != '/')){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Path:[%s] Error.\n",
			pPath);
		return -1;
	}

	pModule = NULL;
	pPath 	+= 1;
	pPos  	= strchr(pPath, '/');
	if(pPos != NULL){
		lenApp = pPos - pPath;
		if(lenApp >= S_APP_MAX_NAME){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Mod:[%s] Error.\n",
				pPath);
			return -1;
		}
		strncpy(modName, pPath, lenApp);
		modName[lenApp]	= '\0';
		/* Now Let's Get the Module */
		modId = SStrJ_S2Int(modName);
		if(modId < 0){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Mod:[%s] Error.\n",
				modName);
			return -1;
		}
		
		SYS_ENTER_CS(&(pAppAgt->agtLock));
		pModule = _SAgtApp_ModGet(pAppAgt, modId);
		SYS_LEAVE_CS(&(pAppAgt->agtLock));
		
		if(pModule == NULL){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Mod:[%s] Error.\n",
				modName);
			return -1;
		}
		lenApp = strlen(pPos);
		if(lenApp >= S_APP_MAX_PATH){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt SubPath:[%s] Error.\n",
				pPos);
			return -1;
		}
		strncpy(pSubPath, pPos, lenApp);
		pSubPath[lenApp] = '\0';
		*ppModule = pModule;	
		return 1;
	}
	else{
		*ppModule = NULL;
		return 0;
	}
	return -1;
}

static 	int 	_SAgtApp_CmdError( _t_appAgt * 	pAppAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* pRspElem;
	int 			len;
	char 			errStr[S_CLI_MAX_PARAM];

	len = SYS_SNPRINTF(	errStr, S_CLI_MAX_PARAM, 
					"Command Error.\n");
	
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_ERROR;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	
	SYS_MEMCPY(pRspElem->reqRsp, errStr, len);
	pRspElem->reqRsp[len]= '\0';
	len += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;

	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtApp_CmdOk( _t_appAgt * 	pAppAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* pRspElem;
	int 			len;
	char 			okStr[S_CLI_MAX_PARAM];

	len = SYS_SNPRINTF(	okStr, S_CLI_MAX_PARAM, 
					"Command Ok.\n");
	
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_OK;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	
	SYS_MEMCPY(pRspElem->reqRsp, okStr, len);
	pRspElem->reqRsp[len]= '\0';
	len += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;

	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtApp_CmdLs( _t_appAgt * 	pAppAgt,
										char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* 	pRspElem;
	int 				i, count, len;

	_t_appModule * 	pModule;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;

	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_LS;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;

	len 	= 0;
	outLen -= sizeof(_t_sysMsgElem)+2; /* For '\n', '\0' Use */

	/* Let's go through all the Module */
	pQue 	= &(pAppAgt->modQue);
	count 	= pQue->count;
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_DEBUG, "AppAgt [%d]Moudles.\n", count);
	
	for(i=0, pNode=pQue->next; 
		i<count; 
		i++, pNode=pNode->next){
		pModule = _O_PARENT(_t_appModule, modNode, pNode);

		len += SYS_SNPRINTF(pRspElem->reqRsp+len, outLen-len,  _CLI_FMT_APP_MODULE, 
							pModule->modId,
							pModule->modReg.modStr);
		if(len >= outLen){
			break;
		}
	}
	pRspElem->reqRsp[len]= '\n';
	pRspElem->reqRsp[len+1]= '\0';
	len += 2;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;
	return 	(pRspElem->msgElem.length);					
}


static 	int 	_SAgtApp_CmdLCmd( _t_appAgt * 	pAppAgt,
											char * outBuf, 	int    outLen)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand* pCommand;
	_t_cliElemRsp* pRspElem;
	int 			i, count, total;

	if((!pAppAgt) || (!outBuf)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Error.\n");
		return -1;
	}

	/* Init the pRspElem */
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_LCMD;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	outLen -= sizeof(_t_sysMsgElem) + 2; /* For '\n', '\0' */
	outBuf 	= pRspElem->reqRsp;
	
	pQue  = &(pAppAgt->cmdTbl.cmdQue);
	count = pQue->count;
	total = 0;

	for(i=0, pNode = pQue->next; i<count; i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, cmdNode, pNode);

		if(strlen(pCommand->cmdReg.cmd) == 0)
			continue;

		total += SYS_SNPRINTF(outBuf+total, outLen - total, _CLI_FMT_APP_COMMAND, pCommand->cmdReg.cmd);

		/* Judge Buffer */
		if(total >= outLen){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt:[%s] CmdLs Rsp Buffer [%d - %d] Overflow.\n", 
				pAppAgt->agtName, total, outLen);
			break;
		}
	}
	
	pRspElem->reqRsp[total]  	= '\0';
	total += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + total;
		
	return pRspElem->msgElem.length;
}


static 	int 	_SAgtApp_CmdExec( _t_appAgt * 	pAppAgt,
											char * outBuf, 	int   outLen,
											char * pCmdStr,
											char * pParam)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand* pCommand;
	_t_cliElemRsp* pRspElem;
	_t_cbentry * pCbEntry;
	int 			i, len, ret, hashKey;
	
	if((!pAppAgt) || (!outBuf) || (!pCmdStr) || (!pParam) || (outLen <= 0)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Error.\n");
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pAppAgt->cmdTbl.hashQue[hashKey]);

	for(i=0, ret=-1, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Command:[%s].\n", pCmdStr);
			ret = 0;
			break;
		}
	}
	
	if(ret == -1){
		/* Judge Buffer */
		if((sizeof(_t_sysMsgElem) + strlen(_gCmdNExist_AppAgt)) >= outLen){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt:[%s] CmdExec Rsp Buffer Overflow.\n", 
				pAppAgt->agtName);
			return -1;
		}
		/* Init the pRspElem */
		pRspElem = (_t_cliElemRsp *)outBuf;

		len = strlen(_gCmdNExist_AppAgt);
		pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
		pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
		pRspElem->msgElem.reserv= 0;
		SYS_MEMCPY(pRspElem->reqRsp, _gCmdNExist_AppAgt, len);
		pRspElem->reqRsp[len] = '\0';
		len += 1;
		pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;
		ret  	= (sizeof(_t_sysMsgElem) + len);
	}

	else{
		pCbEntry = &(pCommand->cmdReg.func);
		if(pCbEntry->cbProc){
			/* Init the Output Buf for CallBack Entry */
			pRspElem = (_t_cliElemRsp *)outBuf;
			pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
			pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
			pRspElem->msgElem.reserv= 0;
			pRspElem->reqRsp[0] = '\0';

			outBuf  += sizeof(_t_sysMsgElem);
			outLen 	-= sizeof(_t_sysMsgElem) + 2;
			ret = pCbEntry->cbProc(	pCbEntry->pArg,
									pCbEntry->lArg,
									pAppAgt,
									outBuf,
									outLen,
									pParam);
			if( (ret >= 0) && (ret < outLen)){
				pRspElem->reqRsp[ret]='\0';
				ret += 1;
				pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + ret;
				ret += sizeof(_t_sysMsgElem);
			}
			else{
				SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt:[%s] CmdExec Rsp Buffer [%d - %d] Overflow.\n", 
					pAppAgt->agtName, ret, outLen);
				ret = -1;
			}
		}
	}
	
	return ret;
}

#define _SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret) 	\
	do{\
		if(ret > 0){\
			(pCmdHdr)->length = ret + sizeof(_t_cliCmdHdr);\
			ret = SockTx_Unix((pAppAgt)->sockCli, outBuf, (pCmdHdr)->length, pSockAddr);\
		}else{\
			return -1;\
		}\
	}while(0)

static  int 	_SAgtApp_CliProc(	_t_appAgt 	  * pAppAgt, 
									_t_cliElemReq *	pReqElem,
									unsigned char * outBuf, 
									unsigned int 	ipAddr, 
									unsigned short 	port,
									S_SOCKET_ADDRUX*pSockAddr)
{
	int 	ret, bHasSub;
	int		lenPath, lenParam, lenCmd;
	
	/* Command Response */
	_t_sysMsgElem 	* 	pMsgElemReq;
	_t_cliCmdRsp 	* 	pRspCmd;
	_t_cliElemRsp	* 	pRspElem;

	/* Msg Header & Element */
	_t_cliCmdHdr 	*	pCmdHdr;

	_t_appModule 	* 	pModule;
	/* Sub Path */
	char 			* 	pPath;
	char 			 	subPath[S_APP_MAX_PATH + 1];

	/* Check Msg Elem */
	pMsgElemReq = (_t_sysMsgElem *)(&pReqElem->msgElem);
	if(pMsgElemReq->dir != _CLI_MSG_ELEM_REQ){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Dir Error.\n");
		return -1;
	}

	lenCmd		= strlen(pReqElem->cmd);
	lenPath 	= strlen(pReqElem->path);
	lenParam	= strlen(pReqElem->param);
	if( (lenCmd >= S_CLI_MAX_CMD) || (lenPath >= S_APP_MAX_PATH) || (lenParam >= S_CLI_MAX_PARAM)){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Content Length Error.\n");
		return -1;
	}

	/* Path Process, Let's Find out Which Applet is Command Route */
	pModule = NULL;
	bHasSub = 0;
	subPath[0]='/'; subPath[1]='\0';
	if(lenPath){
		pPath	= pReqElem->path;
		ret 	= _SAgtApp_CliModGet(pAppAgt, pPath, lenPath, &pModule, subPath);
		if(ret == -1){
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Module Not Found.\n");
			return -1;
		}
		else if(ret == 1){
			bHasSub = 1;	
		}
	}
	SYS_TRACE(_gTraceLvl_AppL, TRACELVL_DEBUG, "AppAgt CliMsg [%s - %s -%s].\n", 
		pReqElem->path, pReqElem->cmd, pReqElem->param);

	/* Command Process, Prepare the Rsp Msg */
	pRspCmd 	= (_t_cliCmdRsp *)outBuf;
	pCmdHdr 	= &(pRspCmd->cmdHdr);
	CLI_CMDHDR_INIT(pCmdHdr, ipAddr, port);
	
	pRspElem	= pRspCmd->rspElem;
	switch(pMsgElemReq->type){
		case _CLI_CMD_CD:
			SYS_ENTER_CS(&(pAppAgt->agtLock));
			if(bHasSub == 1){
				/* We Now Only Support Level 1 Module */
				if( (subPath[0]=='/') && (subPath[1]=='\0')){
					ret = _SAgtApp_CmdOk(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
				}
				else{
					ret = _SAgtApp_CmdError(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
					
				}
			}
			else{
				ret = _SAgtApp_CmdOk(pAppAgt,
									(char *)pRspElem, 
									S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
			}
			SYS_LEAVE_CS(&(pAppAgt->agtLock));

			/* Check Result */
			_SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret);
			break;
			
		case _CLI_CMD_LS:
			SYS_ENTER_CS(&(pAppAgt->agtLock));
			if(bHasSub == 1){
				/* We Now Only Support Level 1 Module */
				if( (subPath[0]=='/') &&
					(subPath[1]=='\0')){
					ret = _SAgtApp_CmdOk(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
				}
				else{
					ret = _SAgtApp_CmdError(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
					
				}
			}
			else{
				ret = _SAgtApp_CmdLs(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
			}
			SYS_LEAVE_CS(&(pAppAgt->agtLock));
			
			/* Check Result */
			_SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret);
			break;
			
		case _CLI_CMD_LCMD:
			ret = 0;
			SYS_ENTER_CS(&(pAppAgt->agtLock));
			if(bHasSub == 1){
				ret = _SAgtApp_ModCmd_Ls(pModule, (char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
			}
			else{
				ret = _SAgtApp_CmdLCmd(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
			}
			SYS_LEAVE_CS(&(pAppAgt->agtLock));
			
			/* Check Result */
			_SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret);
			break;
			
		case _CLI_CMD_EXEC:
			SYS_ENTER_CS(&(pAppAgt->agtLock));
			if(bHasSub == 1){
				ret = _SAgtApp_ModCmd_Exec(pModule, (char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr),
										pReqElem->cmd,
										pReqElem->param);
			}
			else{
				ret = _SAgtApp_CmdExec(pAppAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr),
										pReqElem->cmd,
										pReqElem->param);
			}
			SYS_LEAVE_CS(&(pAppAgt->agtLock));
			
			/* Check Result */
			_SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret);
			break;
			
		default:
			SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt CliMsg Unknown Type:[%d].\n", 
						pMsgElemReq->type);
			return -1;
			break;
	}
		
	return 0;
}

static 	int 	_SAgtApp_CliStub(void 			* 	pArg, int lArg, 
									unsigned char 	* 	pMsg, 	int msgLen, 
									S_SOCKET_ADDRUX *	pSockAddr)
{
	_t_appAgt		* 	pAppAgt;

	/* Command Request */
	_t_cliCmdReq 	*	pReqCmd;
	_t_cliElemReq	*	pReqElem;

	/* Command Response */
	_t_cliCmdRsp 	* 	pRspCmd;
	_t_cliElemRsp	* 	pRspElem;

	/* Msg Header & Element */
	_t_cliCmdHdr 	*	pCmdHdr;

	/* Command Parse */
	int 				ret;
	unsigned int 		ipAddr;
	unsigned short 		port;

	/* Route / Response Buffer */
	unsigned char 		outBuf[S_CLI_MAX_MSG];

	pAppAgt = (_t_appAgt *)pArg;
	if(!pAppAgt)
		return -1;
	
	if(pMsg && (msgLen > 0)){
		/* Check Message */
		pReqCmd = (_t_cliCmdReq *)pMsg;
		pCmdHdr= &(pReqCmd->cmdHdr);
		ipAddr 	= pCmdHdr->ipAddr;
		port 	= pCmdHdr->port;	

		/* Process the Message */
		pReqElem= (_t_cliElemReq *)(pReqCmd->reqElem);

		if(_SAgtApp_CliProc(pAppAgt, pReqElem, outBuf, ipAddr, port, pSockAddr) == -1){
			/* Command Error, Prepare the Rsp Msg */
			pRspCmd 	= (_t_cliCmdRsp *)outBuf;
			pCmdHdr 	= &(pRspCmd->cmdHdr);
			CLI_CMDHDR_INIT(pCmdHdr, ipAddr, port);

			pRspElem 	= pRspCmd->rspElem;
			ret = _SAgtApp_CmdError(pAppAgt, (char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));

			_SAGTAPP_CMD_RSP(pAppAgt, pCmdHdr, pSockAddr, outBuf, ret);
			return -1;
		}
		return 0;
	}
	return -1;
}

#define _SAGT_APP_CLI_TO 	10000
static 	void * 	_SAgtApp_Cli(_t_appAgt* pAppAgt)
{
	int 				ret;
	_t_cbentry 		cbEntry;
	
	/* Check AppAgt Init */
	if(pAppAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_AppL, TRACELVL_ERROR, "AppAgt Not Init.\n");
		return NULL;
	}

	_CBENTRY_INIT(&(cbEntry), _SAgtApp_CliStub, pAppAgt, 0);
	
	while(1){
		ret = SockRxSel_Unix(pAppAgt->sockCli, &cbEntry, _SAGT_APP_CLI_TO);
	}
	
	return NULL;
}

/* -----------------------------------------------------------------------
**	Interface Of AppAgt
**
*/
int 	SAgtApp_Init(char * appName)	
{
	return _SAgtApp_Init(&_gAgt_App, appName);
}

int 	SAgtApp_ModReg(	_t_appModReg  *	pReg)
{
	return _SAgtApp_ModReg(&_gAgt_App, pReg);
}

int 	SAgtApp_ModRegA(_t_appModReg ** ppReg, int count)
{
	return _SAgtApp_ModRegA(&_gAgt_App, ppReg, count);
}

int 	SAgtApp_Exec(_t_cbentry * pCbPost)
{
	return _SAgtApp_Exec(&_gAgt_App, pCbPost);
}

int 	SAgtApp_Fini(void)
{
	return 	_SAgtApp_Fini(&_gAgt_App);
}


